package com.example.xss.commom;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.example.xss.commom.enums.IError;
import com.example.xss.commom.excetion.ApiException;

import java.util.Map;

/**
 * 断言<br>
 * 断言某些对象或值是否符合规定，否则抛出异常。经常用于做变量检查
 * @author WANGJIET24
 * @date 2021-6-8$
 */
public class ApiAssert {
    /**
     * 断言是否为真，如果为 {@code false} 抛出 {@code ApiException} 异常<br>
     *
     *
     * @param expression 布尔值
     * @throws ApiException if expression is {@code false}
     */
    public static void isTrue(boolean expression) throws ApiException {
        isTrue(expression, "[Assertion failed] - this expression must be true");
    }


    /**
     * 断言是否为真，如果为 {@code false} 抛出 {@code ApiException} 异常<br>
     *
     *
     * @param expression 布尔值
     * @param error 异常枚举 {@link com.vangelis.demo.commom.enums.ErrorEnum}
     * @throws ApiException if expression is {@code false}
     */
    public static void isTrue(boolean expression, IError error) throws ApiException {
        if (!expression) {
            throw new ApiException(error);
        }
    }



    /**
     * 断言是否为真，如果为 {@code false} 抛出 {@code ApiException} 异常<br>
     * @param expression 布尔值
     * @param message 错误异常
     */
    public static void isTrue(boolean expression, String message) throws ApiException {
        if (!expression) {
            throw new ApiException(message);
        }
    }

    /**
     * 断言是否为假，如果为 {@code true} 抛出 {@code ApiException} 异常<br>
     * @param expression 布尔值
     * @param message 错误异常
     */
    public static void isFalse(boolean expression, String message) throws ApiException{
        if (expression) {
            throw new ApiException(message);
        }
    }

    /**
     * 断言是否为假，如果为 {@code true} 抛出 {@code ApiException} 异常<br>
     * @param expression 布尔值
     * @param error 异常枚举 {@link com.vangelis.demo.commom.enums.ErrorEnum}
     */
    public static void isFalse(boolean expression, IError error) throws ApiException{
        if (expression) {
            throw new ApiException(error);
        }
    }
    /**
     * 断言是否为假，如果为 {@code true} 抛出 {@code ApiException} 异常<br>
     *
     * <pre class="code">
     * Assert.isFalse(i &lt; 0, "The value must be greater than zero");
     * </pre>
     *
     * @param expression       布尔值
     * @param errorMsgTemplate 错误抛出异常附带的消息模板，变量用{}代替
     * @param params           参数列表
     * @throws ApiException if expression is {@code false}
     */
    public static void isFalse(boolean expression, String errorMsgTemplate, Object... params) throws ApiException {
        isFalse(expression, StrUtil.format(errorMsgTemplate, params));
    }

    /**
     * 断言是否为假，如果为 {@code true} 抛出 {@code ApiException} 异常<br>
     *
     * <pre class="code">
     * Assert.isFalse(i &lt; 0);
     * </pre>
     *
     * @param expression 布尔值
     * @throws ApiException if expression is {@code false}
     */
    public static void isFalse(boolean expression) throws ApiException {
        isFalse(expression, "[Assertion failed] - this expression must be false");
    }

    /**
     * 检查给定字符串是否为空，为空抛出自定义异常，并使用指定的函数获取错误信息返回。
     * @param <T>           字符串类型
     * @param text          被检查字符串
     * @param error 异常枚举 {@link com.vangelis.demo.commom.enums.ErrorEnum}
     * @return 非空字符串
     * @throws ApiException 被检查字符串为空抛出此异常
     * @see StrUtil#isNotEmpty(CharSequence)
     */
    public static <T extends CharSequence> T notEmpty(T text, IError error) throws ApiException {
        if (StrUtil.isEmpty(text)) {
            throw new ApiException(error);
        }
        return text;
    }

    /**
     * 检查给定字符串是否为空，为空抛出自定义异常，并使用指定的函数获取错误信息返回。
     * 判断的是 null和length 空格的字符不为空
     * @param <T>           字符串类型
     * @param text          被检查字符串
     * @param error 异常错误提示
     * @return 非空字符串
     * @throws ApiException 被检查字符串为空抛出此异常
     * @see StrUtil#isNotEmpty(CharSequence)
     */
    public static <T extends CharSequence> T notEmpty(T text, String error) throws ApiException {
        if (StrUtil.isEmpty(text)) {
            throw new ApiException(error);
        }
        return text;
    }

    /**
     * 检查给定字符串是否为空，为空抛出 {@link ApiException}
     *
     * <pre class="code">
     * Assert.notEmpty(name, "Name must not be empty");
     * </pre>
     *
     * @param <T>              字符串类型
     * @param text             被检查字符串
     * @param errorMsgTemplate 错误消息模板，变量使用{}表示
     * @param params           参数
     * @return 非空字符串
     * @throws ApiException 被检查字符串为空
     * @see StrUtil#isNotEmpty(CharSequence)
     */
    public static <T extends CharSequence> T notEmpty(T text, String errorMsgTemplate, Object... params) throws ApiException {
        return notEmpty(text, StrUtil.format(errorMsgTemplate, params));
    }
    /**
     * 检查给定字符串是否为空，为空抛出 {@link ApiException}
     *
     * <pre class="code">
     * Assert.notEmpty(name);
     * </pre>
     *
     * @param <T>  字符串类型
     * @param text 被检查字符串
     * @return 被检查的字符串
     * @throws ApiException 被检查字符串为空
     * @see StrUtil#isNotEmpty(CharSequence)
     */
    public static <T extends CharSequence> T notEmpty(T text) throws ApiException {
        return notEmpty(text, "[Assertion failed] - this String argument must have length; it must not be null or empty");
    }
    /**
     * 断言对象是否不为{@code null} ，如果为{@code null} 抛出指定类型异常
     * 并使用指定的函数获取错误信息返回
     * <pre class="code">
     * Assert.notNull(clazz, ()-&gt;{
     *      // to query relation message
     *      return new ApiException("relation message to return");
     *  });
     * </pre>
     *
     * @param <T>           被检查对象泛型类型
     * @param object        被检查对象
     * @param message 错误
     * @return 被检查后的对象
     */
    public static <T> T notNull(T object, String message) throws ApiException {
        if (null == object) {
            throw new ApiException(message);
        }
        return object;
    }

    /**
     * 断言对象是否不为{@code null} ，如果为{@code null} 抛出指定类型异常
     * 并使用指定的函数获取错误信息返回
     * <pre class="code">
     * Assert.notNull(clazz, ()-&gt;{
     *      // to query relation message
     *      return new ApiException("relation message to return");
     *  });
     * </pre>
     *
     * @param <T>           被检查对象泛型类型
     * @param object        被检查对象
     * @param message 异常枚举 {@link com.vangelis.demo.commom.enums.ErrorEnum}
     * @return 被检查后的对象
     */
    public static <T> T notNull(T object, IError message) throws ApiException {
        if (null == object) {
            throw new ApiException(message);
        }
        return object;
    }


    /**
     * 断言对象是否不为{@code null} ，如果为{@code null} 抛出{@link ApiException} 异常 Assert that an object is not {@code null} .
     *
     * <pre class="code">
     * Assert.notNull(clazz, "The class must not be null");
     * </pre>
     *
     * @param <T>              被检查对象泛型类型
     * @param object           被检查对象
     * @param errorMsgTemplate 错误消息模板，变量使用{}表示
     * @param params           参数
     * @return 被检查后的对象
     * @throws ApiException if the object is {@code null}
     */
    public static <T> T notNull(T object, String errorMsgTemplate, Object... params) throws ApiException {
        return notNull(object, StrUtil.format(errorMsgTemplate, params));
    }


    /**
     * 断言对象是否不为{@code null} ，如果为{@code null} 抛出{@link ApiException} 异常
     *
     * <pre class="code">
     * Assert.notNull(clazz);
     * </pre>
     *
     * @param <T>    被检查对象类型
     * @param object 被检查对象
     * @return 非空对象
     * @throws ApiException if the object is {@code null}
     */
    public static <T> T notNull(T object) throws ApiException {
        return notNull(object, "[Assertion failed] - this argument is required; it must not be null");
    }


    /**
     * 断言对象是否为{@code null} ，如果不为{@code null} 抛出指定类型异常
     * 并使用指定的函数获取错误信息返回
     * <pre class="code">
     * Assert.isNull(value, ()-&gt;{
     *      // to query relation message
     *      return new ApiException("relation message to return");
     *  });
     * </pre>
     *
     * @param object        被检查的对象
     * @param message 错误
     */
    public static  void isNull(Object object, String message) throws ApiException {
        if (null != object) {
            throw new ApiException(message);
        }
    }


    /**
     * 断言对象是否为{@code null} ，如果不为{@code null} 抛出指定类型异常
     * 并使用指定的函数获取错误信息返回
     * <pre class="code">
     * Assert.isNull(value, ()-&gt;{
     *      // to query relation message
     *      return new ApiException("relation message to return");
     *  });
     * </pre>
     *
     * @param object        被检查的对象
     * @param message 错误 异常枚举 {@link com.vangelis.demo.commom.enums.ErrorEnum}
     */
    public static  void isNull(Object object, IError message) throws ApiException {
        if (null != object) {
            throw new ApiException(message);
        }
    }

    /**
     * 断言对象是否为{@code null} ，如果不为{@code null} 抛出{@link ApiException} 异常
     *
     * <pre class="code">
     * Assert.isNull(value, "The value must be null");
     * </pre>
     *
     * @param object           被检查的对象
     * @param errorMsgTemplate 消息模板，变量使用{}表示
     * @param params           参数列表
     * @throws ApiException if the object is not {@code null}
     */
    public static void isNull(Object object, String errorMsgTemplate, Object... params) throws ApiException {
        isNull(object, StrUtil.format(errorMsgTemplate, params));
    }

    /**
     * 断言对象是否为{@code null} ，如果不为{@code null} 抛出{@link ApiException} 异常
     *
     * <pre class="code">
     * Assert.isNull(value);
     * </pre>
     *
     * @param object 被检查对象
     * @throws ApiException if the object is not {@code null}
     */
    public static void isNull(Object object) throws ApiException {
        isNull(object, "[Assertion failed] - the object argument must be null");
    }


    /**
     * 检查给定字符串是否为空白（null、空串或只包含空白符），为空抛出自定义异常。
     * 并使用指定的函数获取错误信息返回
     * <pre class="code">
     * Assert.notBlank(name, ()-&gt;{
     *      // to query relation message
     *      return new ApiException("relation message to return");
     *  });
     * </pre>
     *
     * @param <T>              字符串类型
     * @param text             被检查字符串
     * @param message 错误抛出异常附带的消息生产接口
     * @return 非空字符串
     * @see StrUtil#isNotBlank(CharSequence)
     */
    public static <T extends CharSequence> T notBlank(T text, String message) throws ApiException {
        if (StrUtil.isBlank(text)) {
            throw new ApiException(message);
        }
        return text;
    }


    /**
     * 检查给定字符串是否为空白（null、空串或只包含空白符），为空抛出自定义异常。
     * 并使用指定的函数获取错误信息返回
     * <pre class="code">
     * Assert.notBlank(name, ()-&gt;{
     *      // to query relation message
     *      return new ApiException("relation message to return");
     *  });
     * </pre>
     *
     * @param <T>              字符串类型
     * @param text             被检查字符串
     * @param message 异常枚举 {@link com.vangelis.demo.commom.enums.ErrorEnum}
     * @return 非空字符串
     * @see StrUtil#isNotBlank(CharSequence)
     */
    public static <T extends CharSequence> T notBlank(T text, IError message) throws ApiException {
        if (StrUtil.isBlank(text)) {
            throw new ApiException(message);
        }
        return text;
    }

    /**
     * 检查给定字符串是否为空白（null、空串或只包含空白符），为空抛出 {@link ApiException}
     *
     * <pre class="code">
     * Assert.notBlank(name, "Name must not be blank");
     * </pre>
     *
     * @param <T>              字符串类型
     * @param text             被检查字符串
     * @param errorMsgTemplate 错误消息模板，变量使用{}表示
     * @param params           参数
     * @return 非空字符串
     * @throws ApiException 被检查字符串为空白
     * @see StrUtil#isNotBlank(CharSequence)
     */
    public static <T extends CharSequence> T notBlank(T text, String errorMsgTemplate, Object... params) throws ApiException {
        return notBlank(text, StrUtil.format(errorMsgTemplate, params));
    }

    /**
     * 检查给定字符串是否为空白（null、空串或只包含空白符），为空抛出 {@link ApiException}
     *
     * <pre class="code">
     * Assert.notBlank(name, "Name must not be blank");
     * </pre>
     *
     * @param <T>  字符串类型
     * @param text 被检查字符串
     * @return 非空字符串
     * @throws ApiException 被检查字符串为空白
     * @see StrUtil#isNotBlank(CharSequence)
     */
    public static <T extends CharSequence> T notBlank(T text) throws ApiException {
        return notBlank(text, "[Assertion failed] - this String argument must have text; it must not be null, empty, or blank");
    }


    /**
     * 断言给定数组是否包含元素，数组必须不为 {@code null} 且至少包含一个元素
     * 并使用指定的函数获取错误信息返回
     *
     * <pre class="code">
     * Assert.notEmpty(array, ()-&gt;{
     *      // to query relation message
     *      return new ApiException("relation message to return");
     *  });
     * </pre>
     *
     * @param <T>           数组元素类型
     * @param array         被检查的数组
     * @param message 错误抛出异常附带的消息生产接口
     * @return 被检查的数组
     * @see ArrayUtil#isNotEmpty(Object[])
     */
    public static <T> T[] notEmpty(T[] array, String message) throws ApiException {
        if (ArrayUtil.isEmpty(array)) {
            throw new ApiException(message);
        }
        return array;
    }

    /**
     * 断言给定数组是否包含元素，数组必须不为 {@code null} 且至少包含一个元素
     * 并使用指定的函数获取错误信息返回
     *
     * <pre class="code">
     * Assert.notEmpty(array, ()-&gt;{
     *      // to query relation message
     *      return new ApiException("relation message to return");
     *  });
     * </pre>
     *
     * @param <T>           数组元素类型
     * @param array         被检查的数组
     * @param message 异常枚举 {@link com.vangelis.demo.commom.enums.ErrorEnum}
     * @return 被检查的数组
     * @see ArrayUtil#isNotEmpty(Object[])
     */
    public static <T> T[] notEmpty(T[] array, IError message) throws ApiException {
        if (ArrayUtil.isEmpty(array)) {
            throw new ApiException(message);
        }
        return array;
    }

    /**
     * 断言给定数组是否包含元素，数组必须不为 {@code null} 且至少包含一个元素
     *
     * <pre class="code">
     * Assert.notEmpty(array, "The array must have elements");
     * </pre>
     *
     * @param <T>              数组元素类型
     * @param array            被检查的数组
     * @param errorMsgTemplate 异常时的消息模板
     * @param params           参数列表
     * @return 被检查的数组
     * @throws ApiException if the object array is {@code null} or has no elements
     */
    public static <T> T[] notEmpty(T[] array, String errorMsgTemplate, Object... params) throws ApiException {
        return notEmpty(array, StrUtil.format(errorMsgTemplate, params));
    }

    /**
     * 断言给定数组是否包含元素，数组必须不为 {@code null} 且至少包含一个元素
     *
     * <pre class="code">
     * Assert.notEmpty(array, "The array must have elements");
     * </pre>
     *
     * @param <T>   数组元素类型
     * @param array 被检查的数组
     * @return 被检查的数组
     * @throws ApiException if the object array is {@code null} or has no elements
     */
    public static <T> T[] notEmpty(T[] array) throws ApiException {
        return notEmpty(array, "[Assertion failed] - this array must not be empty: it must contain at least 1 element");
    }


    /**
     * 断言给定数组是否不包含{@code null}元素，如果数组为空或 {@code null}将被认为不包含
     * 并使用指定的函数获取错误信息返回
     * <pre class="code">
     * Assert.noNullElements(array, ()-&gt;{
     *      // to query relation message
     *      return new ApiException("relation message to return ");
     *  });
     * </pre>
     *
     * @param <T>           数组元素类型
     * @param array         被检查的数组
     * @param errorMessage 错误抛出异常附带的消息生产接口
     * @return 被检查的数组
     * @see ArrayUtil#hasNull(Object[])
     */
    public static <T> T[] noNullElements(T[] array, String errorMessage) throws ApiException {
        if (ArrayUtil.hasNull(array)) {
            throw new ApiException(errorMessage);
        }
        return array;
    }


    /**
     * 断言给定数组是否不包含{@code null}元素，如果数组为空或 {@code null}将被认为不包含
     * 并使用指定的函数获取错误信息返回
     * <pre class="code">
     * Assert.noNullElements(array, ()-&gt;{
     *      // to query relation message
     *      return new ApiException("relation message to return ");
     *  });
     * </pre>
     *
     * @param <T>           数组元素类型
     * @param array         被检查的数组
     * @param errorMessage 异常枚举 {@link com.vangelis.demo.commom.enums.ErrorEnum}
     * @return 被检查的数组
     * @see ArrayUtil#hasNull(Object[])
     */
    public static <T> T[] noNullElements(T[] array, IError errorMessage) throws ApiException {
        if (ArrayUtil.hasNull(array)) {
            throw new ApiException(errorMessage);
        }
        return array;
    }

    /**
     * 断言给定数组是否不包含{@code null}元素，如果数组为空或 {@code null}将被认为不包含
     *
     * <pre class="code">
     * Assert.noNullElements(array, "The array must have non-null elements");
     * </pre>
     *
     * @param <T>              数组元素类型
     * @param array            被检查的数组
     * @param errorMsgTemplate 异常时的消息模板
     * @param params           参数列表
     * @return 被检查的数组
     * @throws ApiException if the object array contains a {@code null} element
     */
    public static <T> T[] noNullElements(T[] array, String errorMsgTemplate, Object... params) throws ApiException {
        return noNullElements(array, StrUtil.format(errorMsgTemplate, params));
    }

    /**
     * 断言给定数组是否不包含{@code null}元素，如果数组为空或 {@code null}将被认为不包含
     *
     * <pre class="code">
     * Assert.noNullElements(array);
     * </pre>
     *
     * @param <T>   数组元素类型
     * @param array 被检查的数组
     * @return 被检查的数组
     * @throws ApiException if the object array contains a {@code null} element
     */
    public static <T> T[] noNullElements(T[] array) throws ApiException {
        return noNullElements(array, "[Assertion failed] - this array must not contain any null elements");
    }

    /**
     * 断言给定集合非空
     * 并使用指定的函数获取错误信息返回
     * <pre class="code">
     * Assert.notEmpty(collection, ()-&gt;{
     *      // to query relation message
     *      return new ApiException("relation message to return");
     *  });
     * </pre>
     *
     * @param <E>           集合元素类型
     * @param <T>           集合类型
     * @param collection    被检查的集合
     * @param message 错误信息
     * @return 非空集合
     * @see CollUtil#isNotEmpty(Iterable)
     */
    public static <E, T extends Iterable<E>> T notEmpty(T collection, String message) throws ApiException {
        if (CollUtil.isEmpty(collection)) {
            throw new ApiException(message);
        }
        return collection;
    }

    /**
     * 断言给定集合非空
     * 并使用指定的函数获取错误信息返回
     * <pre class="code">
     * Assert.notEmpty(collection, ()-&gt;{
     *      // to query relation message
     *      return new ApiException("relation message to return");
     *  });
     * </pre>
     *
     * @param <E>           集合元素类型
     * @param <T>           集合类型
     * @param collection    被检查的集合
     * @param message 异常枚举 {@link com.vangelis.demo.commom.enums.ErrorEnum}
     * @return 非空集合
     * @see CollUtil#isNotEmpty(Iterable)
     */
    public static <E, T extends Iterable<E>> T notEmpty(T collection, IError message) throws ApiException {
        if (CollUtil.isEmpty(collection)) {
            throw new ApiException(message);
        }
        return collection;
    }

    /**
     * 断言给定集合非空
     *
     * <pre class="code">
     * Assert.notEmpty(collection, "Collection must have elements");
     * </pre>
     *
     * @param <E>              集合元素类型
     * @param <T>              集合类型
     * @param collection       被检查的集合
     * @param errorMsgTemplate 异常时的消息模板
     * @param params           参数列表
     * @return 非空集合
     * @throws ApiException if the collection is {@code null} or has no elements
     */
    public static <E, T extends Iterable<E>> T notEmpty(T collection, String errorMsgTemplate, Object... params) throws ApiException {
        return notEmpty(collection, StrUtil.format(errorMsgTemplate, params));
    }

    /**
     * 断言给定集合非空
     *
     * <pre class="code">
     * Assert.notEmpty(collection);
     * </pre>
     *
     * @param <E>        集合元素类型
     * @param <T>        集合类型
     * @param collection 被检查的集合
     * @return 被检查集合
     * @throws ApiException if the collection is {@code null} or has no elements
     */
    public static <E, T extends Iterable<E>> T notEmpty(T collection) throws ApiException {
        return notEmpty(collection, "[Assertion failed] - this collection must not be empty: it must contain at least 1 element");
    }

    /**
     * 断言给定Map非空
     * 并使用指定的函数获取错误信息返回
     * <pre class="code">
     * Assert.notEmpty(map, ()-&gt;{
     *      // to query relation message
     *      return new ApiException("relation message to return");
     *  });
     * </pre>
     *
     * @param <K>           Key类型
     * @param <V>           Value类型
     * @param <T>           Map类型
     * @param map           被检查的Map
     * @param message 错误抛出异常附带的消息生产接口
     * @return 被检查的Map
     * @see MapUtil#isNotEmpty(Map)
     */
    public static <K, V, T extends Map<K, V>> T notEmpty(T map, String message) throws ApiException {
        if (MapUtil.isEmpty(map)) {
            throw new ApiException(message);
        }
        return map;
    }

    /**
     * 断言给定Map非空
     * 并使用指定的函数获取错误信息返回
     * <pre class="code">
     * Assert.notEmpty(map, ()-&gt;{
     *      // to query relation message
     *      return new ApiException("relation message to return");
     *  });
     * </pre>
     *
     * @param <K>           Key类型
     * @param <V>           Value类型
     * @param <T>           Map类型
     * @param map           被检查的Map
     * @param message 错误抛出异常附带的消息生产接口
     * @return 被检查的Map
     * @see MapUtil#isNotEmpty(Map)
     */
    public static <K, V, T extends Map<K, V>> T notEmpty(T map, IError message) throws ApiException {
        if (MapUtil.isEmpty(map)) {
            throw new ApiException(message);
        }
        return map;
    }

    /**
     * 断言给定Map非空
     *
     * <pre class="code">
     * Assert.notEmpty(map, "Map must have entries");
     * </pre>
     *
     * @param <K>              Key类型
     * @param <V>              Value类型
     * @param <T>              Map类型
     * @param map              被检查的Map
     * @param errorMsgTemplate 异常时的消息模板
     * @param params           参数列表
     * @return 被检查的Map
     * @throws ApiException if the map is {@code null} or has no entries
     */
    public static <K, V, T extends Map<K, V>> T notEmpty(T map, String errorMsgTemplate, Object... params) throws ApiException {
        return notEmpty(map, StrUtil.format(errorMsgTemplate, params));
    }

    /**
     * 断言给定Map非空
     *
     * <pre class="code">
     * Assert.notEmpty(map, "Map must have entries");
     * </pre>
     *
     * @param <K> Key类型
     * @param <V> Value类型
     * @param <T> Map类型
     * @param map 被检查的Map
     * @return 被检查的Map
     * @throws ApiException if the map is {@code null} or has no entries
     */
    public static <K, V, T extends Map<K, V>> T notEmpty(T map) throws ApiException {
        return notEmpty(map, "[Assertion failed] - this map must not be empty; it must contain at least one entry");
    }
}
